package com.tianqicode.spring.context.support;

import com.tianqicode.spring.beans.BeansException;
import com.tianqicode.spring.beans.factory.config.BeanFactoryPostProcessor;
import com.tianqicode.spring.beans.factory.config.BeanPostProcessor;
import com.tianqicode.spring.beans.factory.config.ConfigurableListableBeanFactory;
import com.tianqicode.spring.context.ApplicationEvent;
import com.tianqicode.spring.context.ApplicationListener;
import com.tianqicode.spring.context.ConfigurableApplicationContext;
import com.tianqicode.spring.context.event.ApplicationEventMulticaster;
import com.tianqicode.spring.context.event.ContextClosedEvent;
import com.tianqicode.spring.context.event.ContextRefreshedEvent;
import com.tianqicode.spring.context.event.SimpleApplicationEventMulticaster;
import com.tianqicode.spring.core.io.DefaultResourceLoader;

import java.util.Collection;
import java.util.Map;

/**
 *  简单地实现常见的上下文功能。 使用模板方法设计模式，需要具体的子类来实现抽象方法。
 *  与普通 BeanFactory 相比，ApplicationContext 应该检测在其内部 bean 工厂中定义的特殊 bean:
 *  因此，此类自动注册BeanFactoryPostProcessors 、 BeanPostProcessors和ApplicationListeners ，它们在上下文中定义为 bean。
 *
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

    /**
     * 具体的广播功能委托给广播器
     */
    private ApplicationEventMulticaster applicationEventMulticaster;

    @Override
    public void refresh() throws BeansException {
        refreshBeanFactory();

        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // ioc1-5: 添加 ApplicationContextAwareProcessor，让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        invokeBeanFactoryPostProcessors(beanFactory);

        registerBeanPostProcessors(beanFactory);

        // ioc1-7新增: 初始化事件发布者
        initApplicationEventMulticaster();

        // ioc1-7新增: 注册事件监听器
        registerListeners();

        // 提前实例化单例Bean对象
        beanFactory.preInstantiateSingletons();

        // ioc1-7新增: 发布容器刷新完成事件
        finishRefresh();
    }

    /**
     * 实例化BeanFactoryPostProcessor并执行
     * @param beanFactory
     */
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    /**
     * 实例化BeanPostProcessor，并将其添加到AbstractBeanFactory中的bean后处理器列表
     * 在之后的实例化bean时，执行处理器
     * @param beanFactory
     */
    protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanPostProcessor> beanPostProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        }
    }

    /**
     * ioc1-7新增:初始化广播器
     */
    private void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
    }

    /**
     * ioc1-7新增:将所有监听器bean注册到广播器中
     */
    private void registerListeners() {
        Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener listener : applicationListeners) {
            applicationEventMulticaster.addApplicationListener(listener);
        }
    }

    /**
     * ioc1-7新增:发布结束刷新事件
     */
    private void finishRefresh() {
        publishEvent(new ContextRefreshedEvent(this));
    }

    /**
     * ioc1-7新增:委托广播器广播事件
     * @param event
     */
    @Override
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return getBeanFactory().getBean(name);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return getBeanFactory().getBean(name, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name, requiredType);
    }

    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    @Override
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    protected abstract ConfigurableListableBeanFactory getBeanFactory();

    protected abstract void refreshBeanFactory() throws BeansException;

    @Override
    public void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    /**
     * ioc1-4新增: 当虚拟机关闭时会调用此方法
     */
    @Override
    public void close() {
        // 发布容器关闭事件
        publishEvent(new ContextClosedEvent(this));

        // 执行销毁单例bean的销毁方法
        getBeanFactory().destroySingletons();
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(requiredType);
    }


}
